package com.monitor.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.*;


public class WxPayUtil {
	private final static String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

	public static final String SOURCES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";

	private static String APPLYID = "wx8f1f7592f9375f84";

	private static String MCHID = "1400932502";

	private static String notify_url = "http://test.niaoyu.net/teacherOrder/payCallback";

	private static String qr_notify_url = "http://test.niaoyu.net/teacherOrder/QRpayCallback";

	private static String KEY = "F0dz9KxxQohGGJntMVwe4eXoYfal0xps";

	private static final String TRANSFERS_PAY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; // 企业付款

    private static final String TRANSFERS_PAY_QUERY = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo"; // 企业付款查询

    private static final String API_SECRET ="671884725628e6c7b69faefde2eb19e5";

    private static final String createOrderURL = "https://api.mch.weixin.qq.com/secapi/pay/refund";         //退款

	/**
	 *
	 * 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串<br>
	 * 实现步骤: <br>
	 *
	 * @param paraMap
	 *            要排序的Map对象
	 * @param urlEncode
	 *            是否需要URLENCODE
	 * @param keyToLower
	 *            是否需要将Key转换为全小写 true:key转化成小写，false:不转化
	 * @return
	 */
	private static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
		String buff = "";
		Map<String, String> tmpMap = paraMap;
		try {
			List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
			// 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
			Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
				@Override
				public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
					return (o1.getKey()).toString().compareTo(o2.getKey());
				}
			});
			// 构造URL 键值对的格式
			StringBuilder buf = new StringBuilder();
			for (Map.Entry<String, String> item : infoIds) {
				if (StringUtils.isNotBlank(item.getKey())) {
					String key = item.getKey();
					String val = item.getValue();
					if (urlEncode) {
						val = URLEncoder.encode(val, "utf-8");
					}
					if (keyToLower) {
						buf.append(key.toLowerCase() + "=" + val);
					} else {
						buf.append(key + "=" + val);
					}
					buf.append("&");
				}

			}
			buff = buf.toString();
			if (buff.isEmpty() == false) {
				buff = buff.substring(0, buff.length() - 1);
			}
		} catch (Exception e) {
			return null;
		}
		return buff;
	}

	public static Map<String, Object> createUnifiedOrder(String money, String openid, String body, int userId,String ordernum, HttpServletResponse response, HttpServletRequest request) throws UnknownHostException {
		System.out.println("微信 统一下单 接口调用");
		// 设置最终返回对象
		Map<String, Object> resultJson = new HashMap<>();
		// 创建条件
		// Criteria criteria = new Criteria();
		Integer total = (int) (Float.parseFloat(money) * 100);
		// 接受参数(金额)
		String amount = total + "";
		// 接口调用总金额单位为分换算一下(测试金额改成1,单位为分则是0.01,根据自己业务场景判断是转换成float类型还是int类型)
		// String amountFen =
		// Integer.valueOf((Integer.parseInt(amount)*100)).toString();
		// String amountFen = Float.valueOf((Float.parseFloat(amount)*100)).toString();
		String amountFen = amount;
		// 创建hashmap(用户获得签名)
		SortedMap<String, String> paraMap = new TreeMap<String, String>();
		// 设置body变量 (支付成功显示在微信支付 商品详情中)
		// String body = "啦啦啦测试";
		// 设置随机字符串
		String nonceStr = generateString(32);
		// 设置商户订单号
		String outTradeNo = ordernum;

		// 设置请求参数(小程序ID)
		paraMap.put("appid", APPLYID);
		// 设置请求参数(商品描述)
		paraMap.put("body", body);
		// 设置请求参数(商户号)
		paraMap.put("mch_id", MCHID);
		// 设置请求参数(随机字符串)
		paraMap.put("nonce_str", nonceStr);
		// 设置请求参数(openid)(在接口文档中 该参数 是否必填项 但是一定要注意 如果交易类型设置成'JSAPI'则必须传入openid)
		paraMap.put("openid", openid);
		// 设置请求参数(商户订单号)
		paraMap.put("out_trade_no", outTradeNo);
		// 设置请求参数(终端IP)
		paraMap.put("spbill_create_ip", InetAddress.getLocalHost().getHostAddress());
		// 设置请求参数(总金额)
		paraMap.put("total_fee", amountFen);
		// 设置请求参数(交易类型)
		paraMap.put("trade_type", "JSAPI");
		// 设置请求参数(通知地址)
		paraMap.put("notify_url", notify_url);
		String attach = userId+"";
		paraMap.put("attach", attach);

		// 调用逻辑传入参数按照字段名的 ASCII 码从小到大排序（字典序）
		String stringA = formatUrlMap(paraMap, false, false);
		// 第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue。(签名)
		String sign = MD5(stringA + "&key=" + KEY).toUpperCase(); // 注：key为商户平台设置的密钥key
		// 将参数 编写XML格式
		StringBuffer paramBuffer = new StringBuffer();
		paramBuffer.append("<xml>");
		paramBuffer.append("<appid>" + APPLYID + "</appid>");
		paramBuffer.append("<body>" + body + "</body>");
		paramBuffer.append("<mch_id>" + MCHID + "</mch_id>");
		paramBuffer.append("<nonce_str>" + paraMap.get("nonce_str") + "</nonce_str>");
		paramBuffer.append("<openid>" + paraMap.get("openid") + "</openid>");
		paramBuffer.append("<out_trade_no>" + paraMap.get("out_trade_no") + "</out_trade_no>");
		paramBuffer.append("<spbill_create_ip>" + paraMap.get("spbill_create_ip") + "</spbill_create_ip>");
		paramBuffer.append("<total_fee>" + paraMap.get("total_fee") + "</total_fee>");
		paramBuffer.append("<trade_type>" + paraMap.get("trade_type") + "</trade_type>");
		paramBuffer.append("<notify_url>" + paraMap.get("notify_url") + "</notify_url>");
		paramBuffer.append("<sign>" + sign + "</sign>");
		paramBuffer.append("<attach>" + attach + "</attach>");
		paramBuffer.append("</xml>");
		System.out.println(paramBuffer.toString());
		try {
			// 发送请求(POST)(获得数据包ID)(这有个注意的地方 如果不转码成ISO8859-1则会告诉你body不是UTF8编码
			// 就算你改成UTF8编码也一样不好使 所以修改成ISO8859-1)
			Map<String, String> map = doXMLParse(getRemotePortData(URL, new String(paramBuffer.toString().getBytes(), "ISO8859-1")));
			// 应该创建 支付表数据
			for(Map.Entry entry: map.entrySet()){
				   System.out.println(entry.getKey()+" = "+entry.getValue());
				}
			System.out.println("微信 统一下单 接口调用成功 并且新增支付信息成功");
			resultJson = generateSignature(map.get("prepay_id"), request, response);
			/*
			 * resultJson.put("package", map.get("prepay_id")); resultJson.put("outTradeNo",
			 * paraMap.get("out_trade_no")); resultJson.put("nonceStr", generateString(32));
			 * resultJson.put("signType", "MD5");
			 *
			 * resultJson.put("paySign", sign);
			 */
			return resultJson;

		} catch (UnsupportedEncodingException e) {
			System.out.println("微信 统一下单 异常：" + e.getMessage());
			e.printStackTrace();
		} catch (Exception e) {
			System.out.println("微信 统一下单 异常：" + e.getMessage());
			e.printStackTrace();
		}
		System.out.println("微信 统一下单 失败");
		return resultJson;
	}

	/**
	 * 扫码支付统一下单返回数据
	 * @param money
	 * @param
	 * @param body
	 * @param userId
	 * @param ordernum
	 * @param response
	 * @param request
	 * @return
	 * @throws UnknownHostException
	 */
	public static Map<String, String> QRcode(String money, String body, int userId,String ordernum, HttpServletResponse response, HttpServletRequest request) throws UnknownHostException {
		System.out.println("微信 统一下单 接口调用");
		// 设置最终返回对象
		Map<String, String> map = new HashMap<>();
		// 创建条件
		// Criteria criteria = new Criteria();
		Integer total = (int) (Float.parseFloat(money) * 100);
		// 接受参数(金额)
		String amount = total + "";
		// 接口调用总金额单位为分换算一下(测试金额改成1,单位为分则是0.01,根据自己业务场景判断是转换成float类型还是int类型)
		// String amountFen =
		// Integer.valueOf((Integer.parseInt(amount)*100)).toString();
		// String amountFen = Float.valueOf((Float.parseFloat(amount)*100)).toString();
		String amountFen = amount;
		// 创建hashmap(用户获得签名)
		SortedMap<String, String> paraMap = new TreeMap<String, String>();
		// 设置body变量 (支付成功显示在微信支付 商品详情中)
		// String body = "啦啦啦测试";
		// 设置随机字符串
		String nonceStr = generateString(32);
		// 设置商户订单号
		String outTradeNo = ordernum;

		// 设置请求参数(小程序ID)
		paraMap.put("appid", APPLYID);
		// 设置请求参数(商品描述)
		paraMap.put("body", body);
		// 设置请求参数(商户号)
		paraMap.put("mch_id", MCHID);
		// 设置请求参数(随机字符串)
		paraMap.put("nonce_str", nonceStr);
		// 设置请求参数(openid)(在接口文档中 该参数 是否必填项 但是一定要注意 如果交易类型设置成'JSAPI'则必须传入openid)
		//paraMap.put("openid", openid);
		// 设置请求参数(商户订单号)
		paraMap.put("out_trade_no", outTradeNo);
		// 设置请求参数(终端IP)
		paraMap.put("spbill_create_ip", InetAddress.getLocalHost().getHostAddress());
		// 设置请求参数(总金额)
		paraMap.put("total_fee", amountFen);
		// 设置请求参数(交易类型)
		paraMap.put("trade_type", "NATIVE");
		// 设置请求参数(通知地址)
		paraMap.put("notify_url", qr_notify_url);
		String attach = userId+"";
		paraMap.put("attach", attach);

		// 调用逻辑传入参数按照字段名的 ASCII 码从小到大排序（字典序）
		String stringA = formatUrlMap(paraMap, false, false);
		// 第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue。(签名)
		String sign = MD5(stringA + "&key=" + KEY).toUpperCase(); // 注：key为商户平台设置的密钥key
		// 将参数 编写XML格式
		StringBuffer paramBuffer = new StringBuffer();
		paramBuffer.append("<xml>");
		paramBuffer.append("<appid>" + APPLYID + "</appid>");
		paramBuffer.append("<body>" + body + "</body>");
		paramBuffer.append("<mch_id>" + MCHID + "</mch_id>");
		paramBuffer.append("<nonce_str>" + paraMap.get("nonce_str") + "</nonce_str>");
		//paramBuffer.append("<openid>" + paraMap.get("openid") + "</openid>");
		paramBuffer.append("<out_trade_no>" + paraMap.get("out_trade_no") + "</out_trade_no>");
		paramBuffer.append("<spbill_create_ip>" + paraMap.get("spbill_create_ip") + "</spbill_create_ip>");
		paramBuffer.append("<total_fee>" + paraMap.get("total_fee") + "</total_fee>");
		paramBuffer.append("<trade_type>" + paraMap.get("trade_type") + "</trade_type>");
		paramBuffer.append("<notify_url>" + paraMap.get("notify_url") + "</notify_url>");
		paramBuffer.append("<sign>" + sign + "</sign>");
		paramBuffer.append("<attach>" + attach + "</attach>");
		paramBuffer.append("</xml>");
		System.out.println(paramBuffer.toString());
		try {
			// 发送请求(POST)(获得数据包ID)(这有个注意的地方 如果不转码成ISO8859-1则会告诉你body不是UTF8编码
			// 就算你改成UTF8编码也一样不好使 所以修改成ISO8859-1)
			map = doXMLParse(getRemotePortData(URL, new String(paramBuffer.toString().getBytes(), "ISO8859-1")));
			// 应该创建 支付表数据
			for(Map.Entry entry: map.entrySet()){
				   System.out.println(entry.getKey()+" = "+entry.getValue());
				}
			System.out.println("微信 统一下单 接口调用成功 并且新增支付信息成功");

			return map;

		} catch (UnsupportedEncodingException e) {
			System.out.println("微信 统一下单 异常：" + e.getMessage());
			e.printStackTrace();
		} catch (Exception e) {
			System.out.println("微信 统一下单 异常：" + e.getMessage());
			e.printStackTrace();
		}
		System.out.println("微信 统一下单 失败");
		return map;
	}

	/**
	 * 方法名: getRemotePortData 描述: 发送远程请求 获得代码示例 参数： @param urls 访问路径 参数： @param
	 * param 访问参数-字符串拼接格式, 例：port_d=10002&port_g=10007&country_a= 创建人: 苏俊源
	 */
	private static String getRemotePortData(String urls, String param) {
		System.out.println("港距查询抓取数据----开始抓取外网港距数据");
		try {
			URL url = new URL(urls);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			// 设置连接超时时间
			conn.setConnectTimeout(30000);
			// 设置读取超时时间
			conn.setReadTimeout(30000);
			conn.setRequestMethod("POST");
			if (StringUtils.isNotBlank(param)) {
				conn.setRequestProperty("Origin", "https://sirius.searates.com");// 主要参数
				conn.setRequestProperty("Referer", "https://sirius.searates.com/cn/port?A=ChIJP1j2OhRahjURNsllbOuKc3Y&D=567&G=16959&shipment=1&container=20st&weight=1&product=0&request=&weightcargo=1&");
				conn.setRequestProperty("X-Requested-With", "XMLHttpRequest");// 主要参数
			}
			// 需要输出
			conn.setDoInput(true);
			// 需要输入
			conn.setDoOutput(true);
			// 设置是否使用缓存
			conn.setUseCaches(false);
			// 设置请求属性
			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
			conn.setRequestProperty("Charset", "UTF-8");

			if (StringUtils.isNotBlank(param)) {
				// 建立输入流，向指向的URL传入参数
				DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
				dos.writeBytes(param);
				dos.flush();
				dos.close();
			}
			// 输出返回结果
			InputStream input = conn.getInputStream();
			int resLen = 0;
			byte[] res = new byte[1024];
			StringBuilder sb = new StringBuilder();
			while ((resLen = input.read(res)) != -1) {
				sb.append(new String(res, 0, resLen));
			}
			return sb.toString();
		} catch (MalformedURLException e) {
			e.printStackTrace();
			System.out.println("港距查询抓取数据----抓取外网港距数据发生异常：" + e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("港距查询抓取数据----抓取外网港距数据发生异常：" + e.getMessage());
		}
		System.out.println("港距查询抓取数据----抓取外网港距数据失败, 返回空字符串");
		return "";
	}

	/**
	 * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。
	 *
	 * @param strxml
	 * @return
	 * @throws JDOMException
	 * @throws IOException
	 */
	private static Map<String, String> doXMLParse(String strxml) throws Exception {
		if (null == strxml || "".equals(strxml)) {
			return null;
		}

		Map<String, String> m = new HashMap<String, String>();
		InputStream in = String2Inputstream(strxml);
		SAXBuilder builder = new SAXBuilder();
		Document doc = builder.build(in);
		Element root = doc.getRootElement();
		List list = root.getChildren();
		Iterator it = list.iterator();
		while (it.hasNext()) {
			Element e = (Element) it.next();
			String k = e.getName();
			String v = "";
			List children = e.getChildren();
			if (children.isEmpty()) {
				v = e.getTextNormalize();
			} else {
				v = getChildrenText(children);
			}

			m.put(k, v);
		}

		// 关闭流
		in.close();

		return m;
	}

	private static InputStream String2Inputstream(String str) {
		return new ByteArrayInputStream(str.getBytes());
	}

	/**
	 * 获取子结点的xml
	 *
	 * @param children
	 * @return String
	 */
	@SuppressWarnings("rawtypes")
	private static String getChildrenText(List children) {
		StringBuffer sb = new StringBuffer();
		if (!children.isEmpty()) {
			Iterator it = children.iterator();
			while (it.hasNext()) {
				Element e = (Element) it.next();
				String name = e.getName();
				String value = e.getTextNormalize();
				List list = e.getChildren();
				sb.append("<" + name + ">");
				if (!list.isEmpty()) {
					sb.append(getChildrenText(list));
				}
				sb.append(value);
				sb.append("</" + name + ">");
			}
		}

		return sb.toString();
	}

	// MD5加密算法
	private static String MD5(String s) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] bytes = md.digest(s.getBytes("utf-8"));
			return toHex(bytes);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private static String toHex(byte[] bytes) {

		final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
		StringBuilder ret = new StringBuilder(bytes.length * 2);
		for (int i = 0; i < bytes.length; i++) {
			ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
			ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
		}
		return ret.toString();
	}

	// 生成随机字符串
	public static String generateString(int length) {
		Random random = new SecureRandom();
		char[] text = new char[length];
		for (int i = 0; i < length; i++) {
			text[i] = SOURCES.charAt(random.nextInt(SOURCES.length()));
		}
		return new String(text);
	}

	/**
	 * 自动生成32位的UUid，对应数据库的主键id进行插入用。
	 *
	 * @return
	 */
	public static String getUUID() {
		/*
		 * UUID uuid = UUID.randomUUID(); String str = uuid.toString(); // 去掉"-"符号
		 * String temp = str.substring(0, 8) + str.substring(9, 13) + str.substring(14,
		 * 18) + str.substring(19, 23) + str.substring(24); return temp;
		 */

		return UUID.randomUUID().toString().replace("-", "");
	}

	public static Map<String, Object> generateSignature(String prepayId, HttpServletRequest request, HttpServletResponse response) {
		System.out.println("微信 支付接口生成签名 方法开始");
		// 实例化返回对象
		Map<String, Object> resultJson = new HashMap<String, Object>();

		// 获得参数(微信统一下单接口生成的prepay_id )
		// 创建 时间戳
		String timeStamp = Long.valueOf(System.currentTimeMillis()).toString();
		// 创建 随机串
		String nonceStr = generateString(32);
		// 创建 MD5
		String signType = "MD5";

		// 创建hashmap(用户获得签名)
		SortedMap<String, String> paraMap = new TreeMap<String, String>();
		// 设置(小程序ID)(这块一定要是大写)
		paraMap.put("appId", APPLYID);
		// 设置(时间戳)
		paraMap.put("timeStamp", timeStamp);
		// 设置(随机串)
		paraMap.put("nonceStr", nonceStr);
		// 设置(数据包)
		paraMap.put("package", "prepay_id=" + prepayId);
		// 设置(签名方式)
		paraMap.put("signType", signType);

		// 调用逻辑传入参数按照字段名的 ASCII 码从小到大排序（字典序）
		String stringA = formatUrlMap(paraMap, false, false);
		// 第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue。(签名)
		String sign = MD5(stringA + "&key=" + KEY).toUpperCase();

		if (StringUtils.isNotBlank(sign)) {
			// 返回签名信息
			resultJson.put("sign", sign);
			// 返回随机串(这个随机串是新创建的)
			resultJson.put("nonceStr", nonceStr);
			// 返回时间戳
			resultJson.put("timeStamp", timeStamp);
			// 返回数据包
			resultJson.put("package", "prepay_id=" + prepayId);

			System.out.println("微信 支付接口生成签名 设置返回值");
		}
		System.out.println("微信 支付接口生成签名 方法结束");
		return resultJson;
	}

	// 回调
	public static void payCallback(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("微信回调接口方法 start");
		System.out.println("微信回调接口 操作逻辑 start");
		String inputLine = "";
		String notityXml = "";
		try {
			while ((inputLine = request.getReader().readLine()) != null) {
				notityXml += inputLine;
			}
			// 关闭流
			request.getReader().close();
			System.out.println("微信回调内容信息：" + notityXml);
			// 解析成Map
			Map<String, String> map = doXMLParse(notityXml);
			// 判断 支付是否成功

			String total_fee = map.get("total_fee");// 金额
			String outTradeNo = map.get("out_trade_no");

			if ("SUCCESS".equals(map.get("result_code"))) {
				System.out.println("微信回调返回是否支付成功：是");
				// 获得 返回的商户订单号
				System.out.println("微信回调返回商户订单号：" + outTradeNo);



				// 访问DB
				// WechatAppletGolfPayInfo payInfo =
				// appletGolfPayInfoMapper.selectByPrimaryKey(outTradeNo);
				// System.out.println("微信回调 根据订单号查询订单状态："+payInfo.getPayStatus());
				/*
				 * if("0".equals(payInfo.getPayStatus())){ //修改支付状态 payInfo.setPayStatus("1");
				 * //更新Bean int sqlRow = appletGolfPayInfoMapper.updateByPrimaryKey(payInfo);
				 * //判断 是否更新成功 if(sqlRow == 1){
				 */
				System.out.println("微信回调  订单号：" + outTradeNo + ",修改状态成功");
				// 封装 返回值
				StringBuffer buffer = new StringBuffer();
				buffer.append("<xml>");
				buffer.append("<return_code>SUCCESS</return_code>");
				buffer.append("<return_msg>OK</return_msg>");
				buffer.append("<xml>");

				// 给微信服务器返回 成功标示 否则会一直询问 咱们服务器 是否回调成功
				PrintWriter writer = response.getWriter();
				// 返回
				writer.print(buffer.toString());
				// }
				// }
			} else {

			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 扫码支付回调
		public static String QRpayCallback(HttpServletRequest request, HttpServletResponse response) {
			System.out.println("微信回调接口方法 start");
			System.out.println("微信回调接口 操作逻辑 start");
			String inputLine = "";
			String notityXml = "";
			try {
				while ((inputLine = request.getReader().readLine()) != null) {
					notityXml += inputLine;
				}
				// 关闭流
				request.getReader().close();
				System.out.println("微信回调内容信息：" + notityXml);
				// 解析成Map
				Map<String, String> map = doXMLParse(notityXml);
				// 判断 支付是否成功

				String total_fee = map.get("total_fee");// 金额
				String outTradeNo = map.get("out_trade_no");

				if ("SUCCESS".equals(map.get("result_code"))) {
					System.out.println("微信回调返回是否支付成功：是");
					// 获得 返回的商户订单号
					System.out.println("微信回调返回商户订单号：" + outTradeNo);



					// 访问DB
					// WechatAppletGolfPayInfo payInfo =
					// appletGolfPayInfoMapper.selectByPrimaryKey(outTradeNo);
					// System.out.println("微信回调 根据订单号查询订单状态："+payInfo.getPayStatus());
					/*
					 * if("0".equals(payInfo.getPayStatus())){ //修改支付状态 payInfo.setPayStatus("1");
					 * //更新Bean int sqlRow = appletGolfPayInfoMapper.updateByPrimaryKey(payInfo);
					 * //判断 是否更新成功 if(sqlRow == 1){
					 */
					System.out.println("微信回调  订单号：" + outTradeNo + ",修改状态成功");
					// 封装 返回值
					StringBuffer buffer = new StringBuffer();
					buffer.append("<xml>");
					buffer.append("<return_code>SUCCESS</return_code>");
					buffer.append("<return_msg>OK</return_msg>");
					buffer.append("<xml>");

					// 给微信服务器返回 成功标示 否则会一直询问 咱们服务器 是否回调成功
					PrintWriter writer = response.getWriter();
					// 返回
					writer.print(buffer.toString());
					// }
					// }
				} else {

				}
				return outTradeNo;
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}
	/**
     * 企业向个人支付转账
     * @param request
     * @param response
     * @param openid 用户openid
     * @param money 金额
     */
    public static Boolean transferPay(HttpServletRequest request, HttpServletResponse response, String openid, String money) {
        //业务判断 openid是否有收款资格

        Map<String, String> restmap = null;
        try {
        	Integer total = (int) (Float.parseFloat(money) * 100);
        	String nonceStr=generateString(32);
        	String partner_trade_no=getUUID();
        	String ip=InetAddress.getLocalHost().getHostAddress();
            Map<String, String> parm = new HashMap<String, String>();
            parm.put("mch_appid", APPLYID); //公众账号appid
            parm.put("mchid", MCHID); //商户号
            parm.put("nonce_str", nonceStr); //随机字符串
            parm.put("partner_trade_no", partner_trade_no); //商户订单号
            parm.put("openid", openid); //用户openid
            parm.put("check_name", "NO_CHECK"); //校验用户姓名选项 OPTION_CHECK
            //parm.put("re_user_name", "安迪"); //check_name设置为FORCE_CHECK或OPTION_CHECK，则必填
            parm.put("amount", total.toString()); //转账金额
            parm.put("desc", "转账到个人"); //企业付款描述信息
            parm.put("spbill_create_ip", ip); //服务器Ip地址
         // 调用逻辑传入参数按照字段名的 ASCII 码从小到大排序（字典序）
    		String stringA = formatUrlMap(parm, false, false);
    		// 第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue。(签名)
    		String sign = MD5(stringA + "&key=" + KEY).toUpperCase(); // 注：key为商户平台设置的密钥key
            parm.put("sign", sign);
            StringBuffer paramBuffer = new StringBuffer();
    		paramBuffer.append("<xml>");
    		paramBuffer.append("<mch_appid>" + APPLYID + "</mch_appid>");
    		paramBuffer.append("<mchid>" + MCHID + "</mchid>");
    		paramBuffer.append("<nonce_str>" + nonceStr + "</nonce_str>");
    		paramBuffer.append("<partner_trade_no>" + partner_trade_no + "</partner_trade_no>");
    		paramBuffer.append("<openid>" + openid + "</openid>");
    		paramBuffer.append("<check_name>NO_CHECK</check_name>");
    		paramBuffer.append("<amount>" + money + "</amount>");
    		paramBuffer.append("<desc>转账</desc>");
    		paramBuffer.append("<sign>" + sign + "</sign>");
    		paramBuffer.append("<spbill_create_ip>" + ip + "</spbill_create_ip>");
    		paramBuffer.append("</xml>");
            restmap = doXMLParse(ssl(TRANSFERS_PAY, new String(paramBuffer.toString().getBytes(), "ISO8859-1")));
        } catch (Exception e) {
           e.getStackTrace();
        }

        if ("SUCCESS".equals(restmap.get("result_code"))) {
            System.out.println("转账成功：" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));
            Map<String, String> transferMap = new HashMap<>();
            transferMap.put("partner_trade_no", restmap.get("partner_trade_no"));//商户转账订单号
            transferMap.put("payment_no", restmap.get("payment_no")); //微信订单号
            transferMap.put("payment_time", restmap.get("payment_time")); //微信支付成功时间
            return true;
        }else {
            if (BlankUtil.isBlank(restmap)) {
            	System.out.println("转账失败：" + restmap.get("err_code") + ":" + restmap.get("err_code_des"));
            }
            return false;
        }
    }

    /**
     * 企业向个人转账查询
     * @param request
     * @param response
     * @param tradeno 商户转账订单号
     * @param callback
     */
    public void orderPayQuery(HttpServletRequest request, HttpServletResponse response, String tradeno,
            String callback) {
        Map<String, String> restmap = null;
        try {
            Map<String, String> parm = new HashMap<String, String>();
            parm.put("appid", APPLYID);
            parm.put("mch_id", MCHID);
            parm.put("partner_trade_no", tradeno);
            parm.put("nonce_str", generateString(32));
            parm.put("sign", "123");


            StringBuffer paramBuffer = new StringBuffer();
    		paramBuffer.append("<xml>");
    		paramBuffer.append("<appid>" + APPLYID + "</mch_appid>");
    		paramBuffer.append("<mch_id>" + MCHID + "</mchid>");
    		paramBuffer.append("<partner_trade_no>" + parm.get("partner_trade_no") + "</partner_trade_no>");
    		paramBuffer.append("<nonce_str>" + parm.get("nonce_str") + "</nonce_str>");
    		paramBuffer.append("<sign>" + parm.get("sign") + "</sign>");
    		paramBuffer.append("</xml>");
            restmap = doXMLParse(ssl(TRANSFERS_PAY_QUERY, new String(paramBuffer.toString().getBytes(), "ISO8859-1")));
        } catch (Exception e) {
            e.getStackTrace();
        }

        if ("SUCCESS".equals(restmap.get("result_code"))) {
            // 订单查询成功 处理业务逻辑
            Map<String, String> transferMap = new HashMap<>();
            transferMap.put("partner_trade_no", restmap.get("partner_trade_no"));//商户转账订单号
            transferMap.put("openid", restmap.get("openid")); //收款微信号
            transferMap.put("payment_amount", restmap.get("payment_amount")); //转账金额
            transferMap.put("transfer_time", restmap.get("transfer_time")); //转账时间
            transferMap.put("desc", restmap.get("desc")); //转账描述
        }else {

        }
    }


    private static String ssl(String url,String data){
        StringBuffer message = new StringBuffer();
        try {
            KeyStore keyStore  = KeyStore.getInstance("PKCS12");
            //FileInputStream instream = new FileInputStream(new File("C:/cert/apiclient_cert.p12"));
            FileInputStream instream = new FileInputStream(new File("/home/tomcat/apache-tomcat-8.5.8/webapps/ROOT/WEB-INF/classes/cert/apiclient_cert.p12"));
            keyStore.load(instream, MCHID.toCharArray());
            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom()
                    .loadKeyMaterial(keyStore, MCHID.toCharArray())
                    .build();
            // Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[] { "TLSv1" },
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            HttpPost httpost = new HttpPost(url);

            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            //System.out.println("executing request" + httpost.getRequestLine());

            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();

                //System.out.println("----------------------------------------");
                //System.out.println(response.getStatusLine());
                if (entity != null) {
                    //System.out.println("Response content length: " + entity.getContentLength());
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
                    String text;
                    while ((text = bufferedReader.readLine()) != null) {
                        message.append(text);
                    }
                }
                EntityUtils.consume(entity);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                response.close();
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        return message.toString();
    }

    /**
     * 退款方法
     * @param orderNo 订单号
     * @param totalFee 订单总金额
     * @param refundFee 退款总金额
     * @return
     */
    public static Boolean refund(String orderNo,String totalFee,String refundFee){
    	Integer total = (int) (Float.parseFloat(totalFee) * 100);
    	Integer refund = (int) (Float.parseFloat(refundFee) * 100);
        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", APPLYID);//应用id
        packageParams.put("mch_id", MCHID);//商户号
        packageParams.put("nonce_str",  generateString(32));//随机字符串
        packageParams.put("out_trade_no", orderNo.trim());//订单号
        packageParams.put("out_refund_no", "refund" + getUUID());//退款单号
        packageParams.put("total_fee",total.toString());//订单总金额Utils.getMoney()
        packageParams.put("refund_fee",refund.toString());//退款总金额
       // packageParams.put("op_user_id", MCHID);//商户号

        String stringA = formatUrlMap(packageParams, false, false);
		// 第二步，在stringA最后拼接上key得到stringSignTemp字符串，并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue。(签名)
		String sign = MD5(stringA + "&key=" + KEY).toUpperCase(); // 注：key为商户平台设置的密钥key
		//packageParams.put("sign", sign);
        String result = "FAIL";
        String msg = "";
        try {
        	String xml= createXML(packageParams, sign);
        	 Map<String, String> restmap = doXMLParse(ssl(createOrderURL, new String(xml.getBytes(), "ISO8859-1")));
            String returnCode =restmap.get("result_code");
            if(returnCode.equals("SUCCESS")){
                result = "SUCCESS";
                msg = "OK";
                int status = -1;
                String resultCode =restmap.get("result_code");
                if(resultCode.equals("SUCCESS")){
                    status = 1;
                }
                if(status == 1) {
                    String outtradeno =restmap.get("out_trade_no"); // 订单号

    //业务操作
                }
                return true;
            }
            if (result.equals("FAIL")) {
                msg = (String)restmap.get("return_msg");

            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return false;
    }

    public static String createXML(Map<String, String> map, String s) throws UnsupportedEncodingException {
        StringBuilder xml = new StringBuilder("<xml>");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String key = entry.getKey();
            String val = entry.getValue();

           xml.append("<").append(key).append(">").append(val).append("</").append(key).append(">");
        }
        xml.append("<").append("sign").append(">").append(s).append("</").append("sign").append(">");
        xml.append("</xml>");
       String xml1=xml.toString();
        return xml1;
    }


    /**
     * 判断微信公众号是否被关注
     *
     */

	public boolean judgeIsFollow(String token,String openid){
	    Integer subscribe = null;
	    String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+token+"&openid="+openid+"&lang=zh_CN";
	    try {
	        URL urlGet = new URL(url);
	        HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
	        http.setRequestMethod("GET"); // 必须是get方式请求
	        http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
	        http.setDoOutput(true);
	        http.setDoInput(true);
	        http.connect();
	        InputStream is = http.getInputStream();
	        int size = is.available();
	        byte[] jsonBytes = new byte[size];
	        is.read(jsonBytes);
	        String message = new String(jsonBytes, "UTF-8");
	        JSONObject demoJson = JSON.parseObject(message);
	        //System.out.println("JSON字符串："+demoJson);
	        subscribe = demoJson.getInteger("subscribe");

	        is.close();
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    return 1==subscribe?true:false;
	}
}
